#include "httpimpl.h"

CHttpIImpl::CHttpIImpl()
{
    m_httpcontent_length = 0;
    m_hstid = HTTP_IMPL_UNKNOWN;
}

CHttpIImpl::~CHttpIImpl(void)
{
    logi("CHttptImpl::~CHttptImpl");
}

HRESULT CHttpIImpl::init_class(const _lComPtr<IAsynFrame>& AsynFrame, const _lComPtr<INetFrame>& Net)
{
    HRESULT hr = S_OK;

    _lComPtr<ITcpSocket> pISocket;
    hr = AsynFrame->CreateIo(io_tcp_ssl_socket, (IBase**)&pISocket.m_p);
    rc_error(hr == S_OK, E_FAIL);

    hr = Net->Create(protocol_dns, (IBase**)&m_pIDns);
    rc_error(hr == S_OK, E_FAIL);

    /*
    hr = this->SetSockOption(SOL_SENDTM, 5);
    rc_error(hr == S_OK, E_FAIL);

    hr = this->SetSockOption(SOL_RECVTM, 5);
    rc_error(hr == S_OK, E_FAIL);

    hr = this->SetSockOption(SOL_CONTM, 5);
    rc_error(hr == S_OK, E_FAIL);

    hr = this->ReadOperationSize(16);
    rc_error(hr == S_OK, E_FAIL);

    hr = this->WriteOperationSize(16);
    rc_error(hr == S_OK, E_FAIL);
    */

    http_init_analyze(http_response);

    varaint_t_init(&m_varurl);
    varaint_t_init(&m_varschema);

    return S_OK;
}

HRESULT CHttpIImpl::BindEvent(IBase* pBase)
{
    m_pHandle.dispose();
    return pBase->QueryInterface(IID_IHttpProc, (void**)&m_pHandle);
}
HRESULT CHttpIImpl::UnBindEvent()
{
    m_pHandle.dispose();
    return S_OK;
}
HRESULT CHttpIImpl::SetCookies(http_header* data)
{
    return S_OK;
}
HRESULT CHttpIImpl::Open(SafeStringPtr addr, SafeStringPtr scheme, unsigned short port)
{
    varaint_t_free_string(&m_varurl);
    varaint_t_free_string(&m_varschema);
    varaint_t_malloc_string(&m_varurl, addr.len, addr.ptr);
    varaint_t_malloc_string(&m_varschema, scheme.len, scheme.ptr);

    return OnConnect(addr.ptr, addr.len);
}
http_header CHttpIImpl::GetHttpHead()
{
    return m_szhttpHead;
}
HRESULT CHttpIImpl::ReSet()
{
    Cancel();
    return S_OK;
}
HRESULT CHttpIImpl::Cancel()
{
    m_hstid = HTTP_IMPL_UNKNOWN;

    http_init_analyze(http_response);

    m_pIDns.dispose();

    varaint_t_free_string(&m_varurl);

    varaint_t_free_string(&m_varschema);

    return S_OK;
}
int CHttpIImpl::IsComplete()
{
    return m_parser->content_length == 0;
}
HRESULT CHttpIImpl::OnComplete(IBase* pOperation, crtid cid, crterr err)
{
    HRESULT hr = S_OK;

    if (err) {
        this->OnNotify(cid, err);
    } else {
        hr = httpEventProc(cid, pOperation);
    }
    return S_OK;
}

HRESULT CHttpIImpl::OnGetHost(crterr error, LPCSTR hostname, LPCSTR host)
{
    if (m_hstid < HTTP_IMPL_CONNECTING && DNS_PROC_RES_NOERROR == error) {
        // httpConnect(m_pIOper.m_p, host, m_uport);
        m_hstid = HTTP_IMPL_CONNECTING;
        return E_FAIL;
    } else {
        if (DNS_PROC_RES_ERROR == error) {
            logi("http->DNS_PROC_RES_ERROR");
        } else {
            logi("http->DNS_ERROR");
        }
        return E_FAIL;
    }
    return S_OK;
}
ULONG CHttpIImpl::OnNotify(crtid cid, crterr err)
{
    rc_error(m_pHandle.m_p != NULL, HTTP_IMPL_UNKNOWN);
    return m_pHandle->OnHttpNotify(cid, err);
}
ULONG CHttpIImpl::Id_Suc(ULONG ulid)
{
    return ulid;
}
ULONG CHttpIImpl::Id_Faild(ULONG ulid)
{
    return ulid;
}

HRESULT CHttpIImpl::httpEventProc(crtid cid, IBase* pOperation)
{
    HRESULT hr = S_OK;

    switch (cid) {
    case HTTP_IMPL_CONNECTING:
        httpConnected(pOperation);
        break;
    case HTTP_IMPL_SEND_HEAD:
        httpSendHeaded(pOperation);
        break;
    case HTTP_IMPL_SEND_BODY:
        httpSendBodyed(pOperation);
        break;
    case HTTP_IMPL_RECV_HEAD:
        httpRecvHeaded(pOperation);
        break;
    case HTTP_IMPL_RECV_BODY:
        httpRecvBodyed(pOperation);
        break;
    default:
        break;
    }

    return hr;
}
HRESULT CHttpIImpl::httpConnected(IBase* pBase)
{
    HRESULT hr = S_OK;

    this->OnNotify(HTTP_IMPL_CONNECTED, S_SUCCESS);

    return hr;
}
HRESULT CHttpIImpl::httpSendHeaded(IBase* pBase)
{
    HRESULT hr = S_OK;

    return hr;
}
HRESULT CHttpIImpl::httpSendBodyed(IBase* pBase)
{
    HRESULT hr = S_OK;

    return hr;
}
HRESULT CHttpIImpl::httpRecvHeaded(IBase* pBase)
{
    HRESULT hr = S_OK;

    // ERROR_CODE errcode = 0;
    // ULONG pTransferedBytes = 0;

    // pOperation->GetResult(&errcode, &pTransferedBytes);

    // ULONG pIoStartPos = 0;
    // ULONG pIoExpectBytes = 0;
    // pOperation->GetIoParam(&pIoStartPos, &pIoExpectBytes);
    //
    // BUFFER_PTR ptr = NULL;
    // pOperation->GetIo(&ptr, &pIoStartPos);
    // rc_error(ptr != NULL,E_FAIL)

    // m_parser->p = ptr;
    // http_analyze((char*)ptr, pTransferedBytes);

    return hr;
}
HRESULT CHttpIImpl::httpRecvBodyed(IBase* pBase)
{
    HRESULT hr = S_OK;
    // BUFFER_PTR ptr = NULL;
    // pOperation->GetIo(&ptr, &pIoStartPos);
    // rc_error(ptr != NULL, E_FAIL)

    // m_parser->p = ptr;
    // http_analyze((char*)ptr, pTransferedBytes);

    return hr;
}

HRESULT CHttpIImpl::httpEvent(crtid event, IBase* pSocket, IBase* pOperation)
{
    HRESULT hr = E_FAIL;

    switch (event) {
    case HTTP_IMPL_SEND_HEAD:
        hr = httpSendHead(pSocket, pOperation);
        break;
    case HTTP_IMPL_SEND_BODY:
        hr = httpSendBody(pSocket, pOperation);
        break;
    case HTTP_IMPL_RECV_HEAD:
        hr = httpRecvHead(pSocket, pOperation);
        break;
    case HTTP_IMPL_RECV_BODY:
        hr = httpRecvBody(pSocket, pOperation);
        break;
    case HTTP_IMPL_END:
        hr = S_OK;
        break;
    default:
        break;
    }
    return hr;
}

HRESULT CHttpIImpl::httpConnect(IOperation* pOperation, NET_ADDR addr, NET_PORT uport)
{
    logi("CHttpClientImpl::httpConnect %s", addr);
    return S_OK; // m_pISocket->ConnectIo(addr, uport, pOperation, HTTP_IMPL_CONNECTING);
}
HRESULT CHttpIImpl::httpSendHead(IBase* pSocket, IBase* pOperation)
{
    const char* p = m_http_resheader.build_res();
    size_t ulen = m_http_resheader.build_res_len();
    return httpSend(HTTP_IMPL_SEND_HEAD, pSocket, pOperation);
}
HRESULT CHttpIImpl::httpSendBody(IBase* pSocket, IBase* pOperation)
{
    return httpSend(HTTP_IMPL_SEND_BODY, pSocket, pOperation);
}
HRESULT CHttpIImpl::httpRecvHead(IBase* pSocket, IBase* pOperation)
{
    return httpRecv(HTTP_IMPL_RECV_HEAD, pSocket, pOperation);
}
HRESULT CHttpIImpl::httpRecvBody(IBase* pSocket, IBase* pOperation)
{
    return httpRecv(HTTP_IMPL_RECV_BODY, pSocket, pOperation);
}

HRESULT CHttpIImpl::httpSend(crtid cid, IBase* pSocket, IBase* pOperation)
{
    // pOperation->SetId(event);
    // return pSocket->WriteIo(pOperation, event);
    return S_OK;
}
HRESULT CHttpIImpl::httpRecv(crtid cid, IBase* pSocket, IBase* pOperation)
{
    // pOperation->SetId(event);
    // return pSocket->ReadIo(pOperation, event);
    return S_OK;
}
void CHttpIImpl::on_http_message_begin()
{
    rc_return(m_parser != NULL);
}
void CHttpIImpl::on_http_header_complete()
{
    rc_return(m_parser != NULL);
    m_httpcontent_length = m_parser->content_length;
    m_szhttpHead = new char[m_parser->nread + 1]();
    memcpy(m_szhttpHead, m_parser->p, m_parser->nread);
}
void CHttpIImpl::on_http_body(const char* at, size_t length)
{
    rc_return(m_parser != NULL)
}
void CHttpIImpl::on_http_message_complete()
{
    rc_return(m_parser != NULL);
}

HRESULT CHttpIImpl::OnConnect(NET_ADDR addr, ULONG addrlen)
{
    HRESULT hr = S_OK;

    CharArrayPtr item;
    item.dispose();
    item = ALLOC_NEW char[1023 + 1]();
    rc_error(item.m_p != NULL, E_FAIL);
    s_strcpy(item, 1023, addr);

    char* port = NULL;
    char* host = NULL;

    host = s_strtok(item, ":", &port);
    rc_error(host != NULL, E_FAIL);
    rc_error(port != NULL, E_FAIL);

    m_uport = atoi(port);

    if (_is_ip(host)) {
    } else {
        // hr = m_pIDns->GetURLtoHost(url, "", "http", this, NULL, NULL, 1);
    }

    return hr;
}
HRESULT CHttpIImpl::OnBuildHttp(http_addr_s url, http_addr_s scheme, NET_PORT uport)
{
    m_http_resheader.set_method(scheme);

    char szPort[32] = {0x00};
    snprintf(szPort, sizeof(szPort), ":%u", uport);
    string strurl(url);
    strurl.append(szPort);
    m_http_resheader.set_host(strurl.c_str());
    m_http_resheader.set_accept("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
    m_http_resheader.set_accept_language("zh-CN");
    m_http_resheader.set_cache_control("no-cache");
    m_http_resheader.set_accept_encoding("gzip, deflate, br");
    m_http_resheader.set_use_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; ServiceUI 13.1) "
                                   "AppleWebKit/537.36 (KHTML, like Gecko) "
                                   "Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134");
    m_http_resheader.build_res_http();

    return S_OK;
}
